题意
给出一个长度为$n$字符串$s$, $m$次询问,每次问你字符串$s$区间内的字符串$l,r$第$k$次出现的位置。
思路
比赛的时候一眼就知道是$sa$但是对于$sa$实在不喜欢,于是比赛的时候整场用$sam$硬怼。已经想到了用主席树记录$endpos$位置,然后从后往前推过去,但是比赛时还不会在$sam$上玩权值线段树合并,赛后学习了一下。
首先,这题我们可以在$sam$上的每个新开节点上存储这个节点是在原串的那个位置是把。
然后对于一个串$i$他的$father$肯定是他的$后缀$ 所以他的$endpos$肯定也是他$father$的$endpos$
同时一个$father$不仅仅只有$i$这个儿子 所以$father$的继承是从很多儿子那边的来的,于是我们需要搞笑处理继承效果,这里用到了权值线段树合并,线段树下标是$endpos$在$s$的位置。
这样我们就可以通过找到一个点而得出这个点所有的$endpos$ ,也可以很快的在权值线段树中找到第$k$大的$endpos $。但是$Q$次查询每次都可能用一个长度$1e5$的串进入$sam$中找这个点的位置,于是我们考虑离线操作,将询问按照$r$排序。但是我们找到了一个点之后可能这个长度太大了,于是我们需要跳到这个点的$father$ 知道这个点的长度刚好大于等于我们需要的长度,这样答案才完整。因为$father$的长度是单调的,于是我们可以考虑用树上倍增 快速找到合适的$father$。
于是这题就愉快的结束了。真爽啊。debug都不需要。
1 |
|